package stud.mpgame.server.game;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import stud.mpgame.net.command.ArrowKeyCommand;
import stud.mpgame.network.Message;
import stud.mpgame.physics.PhysicsWorld;
import stud.mpgame.physics.Vector2D;
import stud.mpgame.server.map.MapData;
import stud.mpgame.snapshot.ASnapshot;
import stud.mpgame.snapshot.ICommand;
import stud.mpgame.snapshot.IGameObject;
import stud.mpgame.snapshot.ISnapshot;

import java.util.ArrayList;
import java.util.List;

public class GameWorld extends ASnapshot {

    private List< Player > players = new ArrayList< Player >();

    private PhysicsWorld physicsWorld;

    public GameWorld(int time, MapData mapData) {
    	super(time);

        this.physicsWorld = new PhysicsWorld(new Vector2D(0, (float)(0.35 * 1e-3)), mapData);
    }
    
    public GameWorld(int deltaTime, GameWorld previous, List< ICommand > commands) {
    	super(deltaTime, previous, commands);

        this.players = new ArrayList< Player >();
        this.physicsWorld = new PhysicsWorld(previous.physicsWorld);

        for(Player player : previous.getPlayers()) {
            Player clone = new Player(player);
            addPlayer(clone);
        }
        update(deltaTime);
    }

    public List< Player > getPlayers() {
        return players;
    }

    public void update(int deltaTime) {
        for ( Player player : players )
            player.update(deltaTime);

        physicsWorld.update(deltaTime);
    }

    public void addPlayer(Player player) {
        players.add(player);

        physicsWorld.addCircle(player.getCircle());
    }

    public void removePlayer(IoSession session) {
        Player currentPlayer = getUser(session);
        players.remove(currentPlayer);

        physicsWorld.removeCircle(currentPlayer.getCircle());
    }

    private Player getUser(IoSession session) {
        for (Player player : players) {
            if (player.getSession().equals(session)) {
                return player;
            }
        }
        return null;
    }

    public void applyArrowKeyCommand(ICommand command) {
        ArrowKeyCommand arrowKeyCommand = (ArrowKeyCommand) command;

        IoSession session = arrowKeyCommand.getSession();
        getUser(session).applyArrowKeyCommand(arrowKeyCommand);
    }

    public String toString() {
        String result = "GameWorld: ";
        result += "TIME = " + getTime() + "\n";
        result += players.size() + " player(s):\n";
        for(Player player : players) {
            result += "id: " + player.getID();
            result += " x: " + player.getX();
            result += " y: " + player.getY();
            result += "\n";
        }
        return result;
    }

    @Override
    public void writeExternal(IoBuffer buffer, Message owner) {
    	super.writeExternal(buffer, owner); //TODO WARNING!
        buffer.putInt(players.size());
    	for(Player player : players) {
    	    player.writeExternal(buffer, owner);
    	}
    }

	public ISnapshot modelNext(int deltaTime, List< ICommand > commands) {	
		return new GameWorld(deltaTime, this, commands);
	}

	@Override
	public List<IGameObject> getAllGameObjects() {
		List<IGameObject> list = new ArrayList<IGameObject>();
		
		//list.addAll(players);
		
		return list;
	}

}
